import { BaseSystem } from '../base';
import { EVENTS, type IEventBus } from '../../events';
import type { PlayerStateSystem } from '../player-state';
import { StoryEngine, type HistoryItem, type StoryState } from './story-engine';
import type {
  StoryConfig,
  StoryItem,
  SuccessEvent,
} from '../../data/story/type';
import { MODEL_NAME } from '../../constants/model-names';
import type { InventoryModel, StoryModel, WalletModel } from '../../model';
import { StoryUtil } from './story-util';
import type { StoryId } from '../../data/story';
import { CURRENCY_TYPE } from '../../model/wallet';
import { ItemReader } from '../item/reader';

const EMPTY_STORY_CONFIG: StoryConfig = {
  items: [],
  successConditions: [],
  successEvents: [],
};

export class StorySystem extends BaseSystem {
  private bus: IEventBus;
  private playerStateSystem: PlayerStateSystem;
  private storyEngine: StoryEngine;

  constructor(bus: IEventBus, playerStateSystem: PlayerStateSystem) {
    super();
    this.bus = bus;
    this.playerStateSystem = playerStateSystem;

    this.storyEngine = new StoryEngine(EMPTY_STORY_CONFIG, playerStateSystem, {
      onStateChange: (state: StoryState) => {
        const storyModel = this.playerStateSystem.getModel<StoryModel>(
          MODEL_NAME.STORY
        );
        storyModel.setCurrentState(state);
      },

      onItemStart: (item: StoryItem) => {
        const storyModel = this.playerStateSystem.getModel<StoryModel>(
          MODEL_NAME.STORY
        );
        storyModel.setCurrentItem(item);
      },

      onStoryEnd: () => {
        const storyModel = this.playerStateSystem.getModel<StoryModel>(
          MODEL_NAME.STORY
        );
        storyModel.setCurrentItem(null);
      },

      onHistoryUpdate: (history: HistoryItem[]) => {
        const storyModel = this.playerStateSystem.getModel<StoryModel>(
          MODEL_NAME.STORY
        );
        storyModel.setHistory(history);
        storyModel.setVisitedNodes(this.storyEngine.getVisitedNodes());
        storyModel.setAchievedFlags(this.storyEngine.getAchievedSuccessFlags());
        storyModel.setHasAchievedAllSuccess(
          this.storyEngine.hasAchievedAllSuccess()
        );
      },

      onEventsTriggered: (events: SuccessEvent[]) => {
        const inventoryModel = this.playerStateSystem.getModel<InventoryModel>(
          MODEL_NAME.INVENTORY
        );
        const storyModel = this.playerStateSystem.getModel<StoryModel>(
          MODEL_NAME.STORY
        );
        const walletModel = this.playerStateSystem.getModel<WalletModel>(
          MODEL_NAME.WALLET
        );
        const storyKey = storyModel.getCurrentStoryKey();
        if (!storyKey) return;
        /** 设置故事完成 */
        storyModel.setStoryCompleted(storyKey);
        /** 处理剧情完成事件 */
        events.forEach((e) => {
          const type = e.cmd;
          switch (type) {
            case EVENTS.INVENTORY_ADD:
              const config = ItemReader.getConfig(e.itemId);
              if (!config) return;
              inventoryModel.addItem(config, e.amount);
              break;
            case EVENTS.WALLET_DEDUCT_SPIRIT_STONE:
              walletModel.spendCurrency(CURRENCY_TYPE.SPIRIT_STONE, e.amount);
              break;
          }
        });
      },
    });

    this.setupEventListeners();
  }

  private setupEventListeners(): void {
    this.bus.on(EVENTS.STORY_NOTIFY_UI_READY, () => {
      this.storyEngine.notifyUIReady();
    });

    this.bus.on(EVENTS.STORY_START, (storyKey: StoryId) => {
      const storyModel = this.playerStateSystem.getModel<StoryModel>(
        MODEL_NAME.STORY
      );
      storyModel.setCurrentStoryKey(storyKey);
      const config = StoryUtil.getStoryData(storyKey);
      this.storyEngine.updateConfig(config);
      this.storyEngine.start();
    });

    this.bus.on(EVENTS.STORY_MAKE_CHOICE, (choiceIndex: number) => {
      this.storyEngine.makeChoice(choiceIndex);
    });

    this.bus.on(EVENTS.STORY_STOP, () => {
      this.storyEngine.stop();
    });
  }
}
